/**
  Let the Balloon fly! 🎈
  Try setting range value between 80 to 100 to see the fly animation.
  
  Note: This pen was initially done in pure js. However, I had to make it running with Vue.js for #UXEChallenge.
  
  #UXEChallenge1
**/

let currentDeltaX = 0;

//Utils
const getElementOffset = el => el.getBoundingClientRect();

const getPercentInBetween = ({ value, min, max }) => {
  return (value - min) / (max - min) * 100;
};

const getValueInBetween = (value, { min, max }) => {
  if (value < min) return min;
  if (value > max) return max;
  return value;
};

const getSliderValue = () => {
  const getRef = ref => app.$refs[ref];
  const { left: thumbElLeft, width: thumbElWidth } = getElementOffset(
  getRef("thumbEl"));

  const { left: inputElLeft, right: inputElRight } = getElementOffset(
  getRef("inputEl"));

  const thumbCenterPoint = thumbElLeft + thumbElWidth / 2;

  const rangeValue = getPercentInBetween({
    value: thumbCenterPoint,
    min: inputElLeft,
    max: inputElRight });


  const percent = Math.round(
  getValueInBetween(rangeValue, { min: 0, max: 100 }));


  return percent;
};

const getBallonScaleValue = () =>
1 + getValueInBetween(getSliderValue(), { min: 1, max: 99 }) / 480;

//-------------------

const app = new Vue({
  el: "main",
  data: {
    isDragging: false,
    percent: 50,
    initialThumbElClientRect: null },

  mounted: function () {
    const getRef = ref => this.$refs[ref];

    TweenLite.set(getRef("thumbEl"), {
      y: "-50%" });


    TweenLite.set(getRef("ballonEl"), {
      rotation: 45 });


    this.initialThumbElClientRect = getElementOffset(getRef("thumbEl"));
  },
  methods: {
    getRef: function (ref) {
      return this.$refs[ref];
    },
    dragStart: function () {
      this.isDragging = true;
      TweenLite.set(this.getRef("ballonEl"), {
        rotation: 45 });

      this.percent = getSliderValue();
      this.toggleSliderAnimation();
    },
    dragEnd: function () {
      this.isDragging = false;
      this.toggleSliderAnimation();
    },
    drag: function (event) {
      if (this.isDragging) {
        const { deltaX: newDeltaX, velocityX } = event;
        const {
          left: thumbElInitialOffsetLeft,
          right: thumbElInitialOffsetRight,
          width: thumbElWidth } =
        this.initialThumbElClientRect;
        const {
          left: inputElOffsetLeft,
          right: inputElOffsetRight } =
        getElementOffset(this.getRef("inputEl"));

        const xMovement = newDeltaX + currentDeltaX;

        const hasGoneTooLeft =
        thumbElInitialOffsetLeft + xMovement <
        inputElOffsetLeft - thumbElWidth / 2;
        const hasGoneTooRight =
        thumbElInitialOffsetRight + xMovement >
        inputElOffsetRight + thumbElWidth / 2;

        if (hasGoneTooLeft || hasGoneTooRight) return;

        this.moveThumb({ x: xMovement, velocityX });
      }
    },
    moveThumb: function ({ x, velocityX }) {
      const sliderValue = getSliderValue();
      const tl = new TimelineLite();

      const scaleValue = getBallonScaleValue();

      tl.
      to(this.getRef("thumbEl"), 0.001, {
        x,
        ease: Power4.ease }).

      to(this.getRef("ballonEl"), 0.2, {
        x,
        scale: scaleValue,
        rotation:
        45 + getValueInBetween(velocityX, { min: -7, max: 7 }) * -15,
        ease: Power4.ease });


      this.getRef("inputEl").style.backgroundImage = `-webkit-gradient(
        linear,
        left top,
        right top,
        color-stop(${sliderValue}%, var(--color-primary)),
        color-stop(${sliderValue}%, var(--color-secondary))
      )`;

      this.percent = sliderValue;
    },

    toggleSliderAnimation: function () {
      const that = this;
      const tl = new TimelineLite();

      const sliderValue = getSliderValue();
      const scaleValue = this.isDragging ? getBallonScaleValue() : 0.8;
      const shouldFlyBalloon = sliderValue >= 80 && sliderValue <= 100;

      const toggleThumbAnim = () => {
        tl.to(that.getRef("thumbEl"), 0.23, {
          width: that.isDragging ? "2.6em" : "1.5em",
          height: that.isDragging ? "2.6em" : "1.5em",
          borderWidth: that.isDragging ? "2px" : "0.5em",
          ease: Power4.easeOut });

      };

      const toggleBallonAnim = () => {
        tl.to(
        that.getRef("ballonEl"),
        0.5,
        {
          opacity: that.isDragging ? 1 : 0,
          scale: scaleValue,
          y: that.isDragging ? "-75%" : "5%",
          ease: that.isDragging ? Power1.easeOut : Power1.easeIn },

        "-0.23");

      };

      if (this.isDragging) {
        toggleThumbAnim();
        toggleBallonAnim();
      } else {
        toggleThumbAnim();
        if (shouldFlyBalloon) {
          tl.to(this.getRef("ballonEl"), 1.7, {
            y: -window.innerHeight / 2,
            opacity: 0,
            ease: Power1.easeOut,
            onComplete: () => {
              TweenLite.set(this.getRef("ballonEl"), {
                y: "5%" });

            } });

        } else {
          toggleBallonAnim();
        }
      }
    } } });



const getRef = ref => app.$refs[ref];

const appHammer = new Hammer.Manager(getRef("thumbEl"));
appHammer.add(new Hammer.Pan({ threshold: 0 }));
appHammer.on("pan", app.drag);
appHammer.on("panend", ({ deltaX }) => {
  currentDeltaX += deltaX;
});

window.addEventListener("mouseup", app.dragEnd, false);
window.addEventListener("touchend", app.dragEnd, false);